





//----------------------------------------------------------------



//-----------------------------------------------------------------------
// Model 1
//
//
//-----------------------------------------------------------------------
double Model ( const int today
              ,const double infection_rate
              ,const int period_incubation
              ,const int period_contagious) {

   // We should not infect the Graph while visiting the Graph,
   //    cause this breaks the logic of updating everybody in a single step.
   // These variables handle that.
   std::set<int> newly_infected, toremove;

   newly_infected.clear ();
   toremove      .clear ();

   // Contagious algorithm:
   //    for each infected person, maybe a neighbor gets infected.
   for (auto carrier: IdxInfected) {

      // Too early to pass disease.
      if (DayStartContagion[carrier] > today) 
         continue;

      // Do not spread disease after X days: remove from contagious algorithm.
      //    https://doi.org/10.1038/s41586-020-2456-9
      //    https://doi.org/10.1101/2020.09.04.20188516
      if (DayStartContagion[carrier] + period_contagious < today) {
         toremove.insert (carrier);
         continue;
      } 

      // Visit neighbors B.
      for (int target : Graph[carrier]) {

         // Very unlucky guy, do not infect him again.
         // (if you did not appreciate the gender and prefer instead to ruin the day
         //  of poor Mary, go ahead and modify the comment).
         if (Infected[target])
            continue;

         // uff. Not this time. This is a global contagious rate,
         //   independent of age; it represents the odds of a potentially contagious contact
         //   between two people. If adjusted to 100%, an infected person will meet
         //   all neighbors everyday.
         if ( ! Probability(infection_rate))
            continue;

         // Unlucky people may get contaminated more than once during a day
         //   by two graph paths (neighbors), but they won't be counted twice.
         if (newly_infected.end() != newly_infected.find (target))
            continue;

         // Given the age of person B, what's the probability of being contaminated?
         double probability = InfectProbability.Probability_Of (Age[target]);


         // Alea iacta est.
         if (!Probability(probability)) {
            continue;
         }

         // Person B gets infected.
         newly_infected.insert (target);

         // Patient A has a new descendent B.
         if (InfectCount.end() != InfectCount.find (target)) {

            fprintf (stderr, "Something horrible happened! %s %d\n", __FILE__, __LINE__);

            exit (1);
         }

         // ...and, at least for now, descendent B has no descendency.
         InfectCount[target] = 0;
         ++InfectCount[carrier];

         if (arqtree.is_open())
            arqtree << " n" << carrier << " -- n" << target << " \n";

      } //for (int target : Graph[carrier]) {

   } // for (auto carrier: IdxInfected) {


   // People who will not pass the disease again is removed 
   //   from the system. They will neither get infected again.
   //   This is a SEIR model.
   for (auto a : toremove) {

      auto x = IdxInfected.find (a);
      if (IdxInfected.end () != x)
         IdxInfected.erase  (x);
      else {
         fprintf (stderr, "Something horrible happened! %s %d\n", __FILE__, __LINE__);
         exit (-1);
      }
   }

   // Update Counters.
   NumberInfectedToday  = newly_infected.size();
   NumberInfectedTotal += NumberInfectedToday;


   // Bookeeping. Pass the virus. Keep counter of patients.
   for (auto a : newly_infected) {

      // Sanity check (should never occur).
      StopProgramIf(IdxInfected.end()!= IdxInfected.find(a),"Algorithm tried to re-infect agent.");

      // Take note of who is this person.
      IdxInfected.insert (a);
      
      // This variable is faster to check than IdxInfected.
      Infected[a] = true;

      DayStartContagion[a] = today + period_incubation;

   }

   return 1;
}
